# -*- coding:utf-8 -*-
from __future__ import unicode_literals

from neo4j.v1 import GraphDatabase

from mainsys.settings import neo4jhost_host


# Neo4j的api类
class Neo4jAPI(object):
    def __init__(self, ):
        driver = GraphDatabase.driver(neo4jhost_host)
        self.session = driver.session()

    def __str__(self):
        return 'Neo4j API'

    # 创建过滤条件
    @staticmethod
    def create_filter(filter_data=None):
        filter_list = []
        # 创建过滤条件
        for key, value in filter_data.items():
            for k, v in value.items():
                if type(v) != list and k != 'regionid':
                    # 正常情况直接等于
                    filter_list.append('%s.%s="%s"' % (key, k, v)) if v else ''
                elif k == 'regionid':
                    # 城市查询需要 starts with
                    filter_list.append('%s.%s starts with "%s"' % (key, k, v)) if v else ''
                elif type(v) == list and len(v) == 2:
                    # 范围查询需要 比较
                    filter_list.append('"%s" <= %s.%s' % (v[0], key, k)) if v[0] else ''
                    filter_list.append('%s.%s <= "%s"' % (key, k, v[1])) if v[1] else ''
        return filter_list

    # 创建查询语句
    @staticmethod
    def node_filter(search, node_list, filter_data):
        if search and node_list and filter_data:
            # 取出skip与limit
            skip = filter_data.pop('skip', 0)
            limit = filter_data.pop('limit', 20)
            # 取出经过的节点和关系
            for index, node in enumerate(node_list):
                node_list[index] = filter_data.get(node, {}).pop('name', None)
                if node.startswith('relationship'):
                    # 添加关系方向
                    direction = filter_data.get(node, {}).pop('direction', None)
                    if direction == '>':
                        search = search.replace('-[' + node + ':%s]-', '-[' + node + ':%s]->')
                    elif direction == '<':
                        search = search.replace('-[' + node + ':%s]-', '<-[' + node + ':%s]-')
            # 添加path层数
            node_list.append(filter_data.pop('depth', 10))
            # 创建过滤条件
            filter_list = Neo4jAPI.create_filter(filter_data)
            # 添加过滤条件
            search += ' where ' + ' and '.join(filter_list)
            #  todo 排序
            search += ' with p, end_node.regcap as regcap order by regcap desc '
            # 返回类型与数量
            search += 'return p skip %s limit %s' % (skip, limit)
            # 移除未指定的节点或关系名
            search = (search % tuple(node_list)).replace(':None', '')
            return search
        return ''

    # 格式化输出
    @staticmethod
    def format_data(result):
        try:
            result_data = []
            # 组装字典
            for x in result:
                data = []
                # 取出节点
                node = list(x['p'].nodes)
                # 取出关系
                relationship = list(x['p'].relationships)
                # 将关系插入节点中间   节点-关系-节点-关系-节点
                result_list = list(reduce(lambda x, y: x + y, zip(node, relationship))) + node[-1:]
                for y in result_list:
                    if hasattr(y, 'type'):
                        # 关系名称 关系属性
                        if y.start == data[-1]['id']:
                            direction = '>'
                        elif y.end == data[-1]['id']:
                            direction = '<'
                        else:
                            direction = ''
                        data.append({y.type: y.properties, 'direction': direction})
                    elif hasattr(y, 'labels'):
                        # 节点名称 节点属性
                        data.append({list(y.labels)[0]: y.properties, 'id': y.id})
                result_data.append(data)
        except Exception as e:
            return e
        else:
            return result_data

    # 节点关系查询
    def find_path(self, filter_data=None):
        if filter_data:
            search = """match (start_node:%s) match (end_node:%s) match p=allShortestPaths((start_node)-[*..%s]-(end_node))"""
            node_list = ['start_node', 'end_node']
            # 拼接查询语句
            search = self.node_filter(search, node_list, filter_data)
            # 执行查询
            result = self.session.run(search)
            return self.format_data(result)
        return []

    # 层次关系查询
    def search(self, filter_data=None, layer=None):
        if filter_data and layer:
            search = ''
            node_list = []
            # 查询一层关系
            if layer == 'one':
                search = """match p=(start_node:%s)-[relationship:%s]-(end_node:%s)"""
                node_list = ['start_node', 'relationship', 'end_node']
            # 查询两层关系
            elif layer == 'two':
                search = """match p=(start_node:%s)-[relationship1:%s]-(middle_node:%s)-[relationship2:%s]-(end_node:%s)"""
                node_list = ['start_node', 'relationship1', 'middle_node', 'relationship2', 'end_node']
            # 拼接查询语句
            search = self.node_filter(search, node_list, filter_data)
            # 执行查询
            result = self.session.run(search)
            return self.format_data(result)
        return []

## 调用示例：
# api = Neo4jAPI()
# filterdata = {
#     'start_node': {
#         'name': 'company',
#         'companyId': '717314',
#     },
#     'relationship1': {
#         'name': 'position',
#     },
#     'middle_node': {
#         'name': 'person',
#     },
#     'relationship2': {
#         'name': 'perinv',
#     },
#     'end_node': {
#         'name': 'company',
#         'companyId': '7234346',
#         'regionid': '11',
#         'nicid': '',
#         'regcap': [1, 100000],
#         'esdate': ['2005-1-1', '2015-1-1']
#     },
#     'skip': 0,
#     'limit': 20,
#     'depth': 10
# }
# result = api.search(filter_data=filterdata, layer='two')
# result = api.find_path(filter_data=filterdata)
